![AWS Migration Hub Refactor Spaces ハンズオンをやってみた #awsbasics](https://devio2023-media.developers.io/wp-content/uploads/2019/05/aws-migration-hub.png)
AWS Migration Hub Refactor Spaces ハンズオンをやってみた #awsbasics
コンバンハ、千葉(幸)です。
re:Invent 2021 の期間中に、Amazon Migration Hub Refactor Spaces がプレビューリリースされました。モノリシックなアーキテクチャからマイクロサービスアーキテクチャへのリファクタリングを助けてくれるサービスです。
せっかく新しいサービスだし触ってみるか!と思いますが、ハードルとなるのがリファクタリング対象のアプリケーションの準備です。自分はマネジメントコンソールからポチポチしてサービスを触ってみたいだけなんじゃ……前提構成としてアプリケーションの準備が必要となるともう手が出せんのじゃ……となっていました。
そんな時にありがたいことに丸っと一式準備してくれているハンズオンが開催されました。
一通り手を動かしてみたので、そのおさらいや所感を書いていきます。
まとめ
- ハンズオンはデプロイの待ち時間を含めて 90 分程度あれば一通り試せる
- Transit Gateway の作成を伴うため、古い AZ(apne1-az3)が有効な環境では失敗する
- 東京リージョン以外を使用することで回避すること
- VPC や Transit Gateway の新規構築を伴うため上限数に注意
- アプリケーションの準備を自前でしなくていいのが助かる!
- 権限不足のエラーを避けるため
AdministratorAccess
を持つユーザーやロールでの試行を推奨 - あくまでハンズオンなので単一アカウント単一 VPC に閉じている
- Refactor Spaces が作成してくれる NLB や Transit Gateway の出番がない
- AWS Migration Hub Refactor Spaces はまだプレビューリリースの段階のため将来的に仕様の変更の可能性あり
ハンズオンで使用する手順や資材
以下に手順や必要な資材がまとめられています。
一式をまとめて ZIP でダウンロードするのが楽です。
内訳は以下となっています。番号はわたしが勝手に振ったものです。
# | ファイル名 | 概要 |
---|---|---|
1 | AWS Migration Hub Refactor Spaces ワークショップ.docx | ハンズオンの手順 |
2 | AWS Migration Hub Refactor Spaces ワークショップ.pdf | #2のPDF版 |
3 | MonoToMicroCF.template.txt | CloudFormationテンプレート |
4 | MonoToMicroCFDDB.yaml.txt | CloudFormationテンプレート |
5 | MonoToMicroLambda-0.0.1.jar | Lambda 関数にデプロイするコード |
6 | README.md | README |
7 | config.json | configのサンプル(使用しなくて可) |
8 | testcommand.txt | コマンド等のメモ |
Refactor Spaces ハンズオンで作成する環境のイメージ
全体像をイメージしておきましょう。
遠回りになりますがそもそも AWS Migration Hub Refactor Spaces を活用する時にはどういったアーキテクチャを取るかを確認します。
AWS Migration Hub Refactor Spaces では、最上位のリソースとして環境(Enviroment)を作成し、その中にアプリケーションというリソースを作成します。環境の中に複数のアプリケーションを作成可能です。
以下画像の左下がひとつのアプリケーションを表します。
(Preview – AWS Migration Hub Refactor Spaces Helps to Incrementally Refactor Your Applications より)
Refactor Spaces 環境およびアプリケーションの作成と合わせて以下の一式が作成され、Refactor Spaces でのサービス設定に応じてよしなに設定変更が行われます。自前での設定変更が最小限で済みます。
- Amazon API Gateway
- Network load balancer
- AWS Transit Gateway
画像の例ではモノリシックアプリケーションとして EC2 +RDS の構成があり、リファクタリングによって一部のパスへのアクセスが Lambda + DynamoDB のマイクロサービスアーキテクチャに切り出されています。Refactor Spaces の「アプリケーション」がプロキシとして機能し、パスに応じて後段に振り分けています。後段のリソースは別の AWS アカウントにあることがベストプラクティスとされています。
それを踏まえて今回のハンズオンで作成される構成が以下です。
すべてのリソースが単一のアカウントに閉じ、Refactor Spaces アプリケーションとモノリスアプリケーションが同一 VPC に相乗りしています。実際に使用する際にはこういった構成は取らないでしょう。
また、フロントに位置する API Gateway エンドポイントから後段の EC2(パブリック DNS) や Lambda 関数に振り分けを行うのですが、直接ルーティングが可能なため今回は NLB や Transit Gateway の出番はありません。
Refactor Spaces ハンズオンの流れ
冒頭で挙げた #1 もしくは #2 の資料を見ながら進めていきます。
便宜上、以下のように整理しました。これはこのエントリために勝手に章番号をつけたものです。
- モノリシックアプリケーションの構築
- CloudFormation スタックのデプロイ
- アプリケーションの確認
- Refactor Spaces の起動
- Refactor Spaces サービスとルートの設定
- Refactor Spaces サービスとルートの作成
- S3 からの向き先変更
- マイクロサービス環境の構築
- DynamoDB の作成
- Lambda 関数の作成
- ストラングラーフィグパターンの構築
- Refactor Spaces サービスの作成(前半)
- API Gateway API モデルの作成
- Refactor Spaces サービスの作成(後半)
- API Gateay API 各種設定変更
元の資料では手順ごとに番号が振られているため、随時それとの紐付けをしていきます。以降、単に「番号」という時は手順内の番号のことを指します。
1. モノリシックアプリケーションの構築
以下の構成を構築します。
#3 MonoToMicroCF.template.txt
を使用するので準備しておきましょう。
1.1. CloudFormation スタックのデプロイ
上記の構成一式が#3 MonoToMicroCF.template.txt
で CloudFormation テンプレートとして定義されているのでデプロイを行います。(番号 1.~6.)
デプロイにはおよそ 20 分程度かかるため、はじめからちょっと待ちの時間が発生します。後続の手順でも眺めながら気楽に待ちましょう。
ここで作成される EC2 はすでにアプリケーションが実装済みの AMI から起動されるため、立ち上げればすぐに触れる状態になっているのがありがたいです。
1.2. アプリケーションの確認
手順としては必須ではありませんが、せっかくなので触っておきましょう。
作成した CloudFormation スタックの出力から各種情報が確認できます。キー WebsiteURL の URL を開いてみましょう。
以下のようなページが作成されています。適当なメールアドレス(ダミーでOK)でサインアップして、カートへの追加などの操作を試してみましょう。
Chrome のデベロッパーツールなどを使用して確認すると、作成された EC2 のパブリック DNS に通信していることが見て取れます。(番号10.)
2. Refactor Spaces の起動
Refactor Spaces の環境およびアプリケーションを作成していきます。
後続の手順で必要になるので、先程の手順でデプロイされた VPC の ID を予め控えておきましょう。
AWS Migration Hub のサービス画面からRefactor Spaces への導線が確保されています。Refactor Spacesの画面に遷移後、リージョンが想定したものであるか確認してください。(番号 11.~12.)
左ペイン「環境」から「環境を作成」を押下します。(番号 13.)
環境の作成は 4 ステップに分かれます。
ステップ 1. 環境を作成
環境名を指定して次に進みます。(番号14.)
環境作成に合わせて Refactor Spaces 用のサービスリンクロール(SLR)が作成されることが示されています。後から確認したところAWSServiceRoleForMigrationHubRefactorSpaces
という名称のロールが作成されていました。
ステップ2. アプリケーションを作成
環境内のアプリケーションを作成します。アプリケーション名の指定とプロキシ VPC の指定を行います。先述の通りこのハンズオンでは EC2 と同じ VPC を指定しますので、先程控えておいた VPC ID を選択します。(番号15.~16.)
VPC やアカウントをまたぐ構成を試してみたい人は別のものを指定してみる、というのも面白いかもしれません。
ステップ3. 環境を共有
このハンズオンでは特に何もせず次に進みます。(番号 17.)
ここで AWS アカウントや Organizations、Organizations OU をプリンシパルとして共有することができるんですね。
ステップ4. 確認
ここまでの設定内容を確認の上、「環境を作成」を押下します。(番号18.)
環境およびアプリケーションの作成が始まります。作成直後はページの移動を行わないように注意が表示されます。
環境の作成は比較的早く終わると思いますが、アプリケーションのヘルスステータスが「正常」になるまではそこそこ時間がかかります。わたしの環境では 15 分弱かかりました。気楽に待ちましょう。(番号 19.)
3. Refactor Spaces サービスとルートの設定
作成した Refactor Spaces アプリケーションがプロキシとして機能するように設定していきます。
EC2 のパブリック DNS 名が必要になるので、手順 1.2. でも参照した CloudFormation スタックの出力から確認しておきましょう。
3.1. Refactor Spaces サービスとルートの作成
Refactor Spaces サービス画面の左ペインから「サービスの作成」を押下します。(番号 20.)
各種情報を入力し、「サービスを作成」を押下します。(番号 21.~25.)
サービスおよびルートの作成が行われます。こちらは数分も経たずに完了しました。(番号 26.)
3.2. S3 からの向き先変更
S3 上の静的ファイルが参照する先はconfig.json
で定義されています。デフォルトでは EC2 のパブリック DNS 名が指定されているため、それを Refactor Spaces アプリケーションで作成された API Gateway のURL に置き換えます。
Refactor Spaces アプリケーションと同一名称のunistore
という API が存在するため、その URL を控えます。(番号 27.~28.)
静的ウェブサイトホスティング有効の S3 バケット MonoToMicro-uibucket-xxxxxからconfig.json
をダウンロードし、その内容を書き換えます。(番号 29.)
{ "host": "https://xxxxxkh4ph.execute-api.ap-northeast-1.amazonaws.com/prod" }
config.json
を S3 へ上書きアップロードします。パブリック公開が必要なため、チェックをつけてください。(番号 30.)
このハンズオンでは問題ありませんが、S3 オブジェクトをパブリック公開する際はその影響をきちんと考慮してください。
ここまでの設定により、Refactor Spaces アプリケーションがプロキシとして機能するようになりました。1.1 で確認した WebsiteURL からページに遷移し、デベロッパーツールなどで確認してみましょう。
通信先が EC2 パブリック DNS から API Gateway の URL に変わっていることが確認できるかと思います。(番号 32.)
4. マイクロサービス環境の構築
ここまでの手順で Refactor Spaces がプロキシとして機能できるようになりました。とは言え今はすべて後段の EC2 に流れていくので、新しい振り分け先となるマイクロサービス環境を作っていきます。
#4 MonoToMicroCFDDB.yaml.txt
と#8 testcommand.txt
を使用するので準備しておきましょう。
4.1. DynamoDB の作成
#4 MonoToMicroCFDDB.yaml.txt
では、DynamoDB テーブルとそれへの書き込み権限を持つ IAM ロールが作成されます。
上記のテンプレートを使用し、MonoToMicrDDB という名称で CloudFormation スタックを作成します。作成が完了したら IAM ロールの名称を確認しておきます。(番号 33.~35.)
4.2. Lambda 関数の作成
ここでは以下 3 つの Lamda 関数を作成します。
- AddUnicornToBasket
- RemoveUnicornFromBasket
- GetUnicornBasket
これらはほぼ同じ設定値を持ち、唯一ランタイム設定のハンドラが異なります。先に 3 種それぞれのハンドラの設定値を記載すると以下の通りです。
com.monoToMicro.Lambda.UnicornBasketImpl::addUnicornToBasket com.monoToMicro.Lambda.UnicornBasketImpl::removeUnicornFromBasket com.monoToMicro.Lambda.UnicornBasketImpl::getUnicornsBasket
代表してひとつ Lambda 関数 AddUnicornToBasket の作成手順を見ていきます。
関数の作成画面から以下のように選択し作成を実行します。(番号 36.~39.)
作成した関数にコードソースをアップロードします。アップロード対象の jar ファイルは CloudFormation によってデプロイされた S3 バケットMonoToMicro-assetbucket-xxxxxからダウンロードできる MonoToMicroLambda-0.0.1.jar です。(番号 40.~42.)
ランタイム設定→編集でハンドラの値を変更します。ハンドラは先述の通りで、AddUnicornToBasket であればcom.monoToMicro.Lambda.UnicornBasketImpl::addUnicornToBasket
を入力します。(番号 43.)
設定としては必須ではありませんが、テストを実施します。テストで入力するイベントドキュメントは#8 testcommand.txt
に記載されています。AddUnicornToBasket であれば以下です。
{ "uuid": "4b3fc86b-81d0-4614-920e-8184063acf2d", "unicorns": [ { "uuid": "16c3e7c0-bba4-11e9-afec-41e09d726297" } ] }
テスト結果が成功となれば完了です。テストによって DynamoDB テーブルに値が増えていることを確認できます。(番号 44.~47.)
残り2つの以下関数も同じ要領で作成します。
- RemoveUnicornFromBasket
- GetUnicornBasket
繰り返しになりますが、ハンドラの値はそれぞれ以下を指定する必要があります。
com.monoToMicro.Lambda.UnicornBasketImpl::removeUnicornFromBasket com.monoToMicro.Lambda.UnicornBasketImpl::getUnicornsBasket
テストに使用するイベントドキュメントは 2 つの関数で共通して以下です。(番号 48.)
{ "uuid": "4b3fc86b-81d0-4614-920e-8184063acf2d" }
5. ストラングラーフィグパターンの構築
作成した Lambda 関数に対して Refactor Spaces からリクエストが流れるようにしていきます。/unicorns/basket
配下のパスへのアクセスは EC2 ではなくLambda 関数にルーティングされるようにします。
先程作成した関数ごとに、Refactor Spaces サービスを作成します。サービスの作成に合わせてルートも作成されます。そして API Gateway でも対応するパスが追加されていくため、その設定変更を行うのがこのステップです。
#8 testcommand.txt
をここでも使用します。
5.1. Refactor Spaces サービスの作成(前半)
まずは以下 2 つの Lambda 関数むけの Refactor Spaces サービスを作成します。
- AddUnicornToBasket
- RemoveUnicornFromBasket
ここではいずれもソースパスの「子パスを含める」にチェックを入れないよう注意していください。
Refactor Spaces のサービス画面から「サービスを作成」を押下し、各種情報を入力の上作成を実行します。以下は AddUnicornToBasket 向けのサービスの例です。(番号 49.~54.)
続いて RemoveUnicornFromBasket 向けのサービスも同様の手順で作成します。サービス名、選択する Lambda 関数が先程とは違うのはもちろんですが、「動詞」をDELETE
にしてあげる必要があります。ソースパス、「子パスを含める」にチェックがつかないのは先程と同様です。(番号 55.)
5.2. API Gateway API モデルの作成
この段階で一旦 API Gateway の画面に映ります。3.2.で確認したのと同様に、Refactor Spaces アプリケーション名(今回であればunistore
)と同じ API を選択します。
Refactor Spaces サービスとして追加した/unicorns/basket
への GET 、DELETE メソッドが追加されていることが確認できるはずです。(番号 56.~58.)
左ペイン「モデル」から「作成」を押下し、モデルを作成します。モデルのスキーマとして指定するのは#8 testcommand.txt
にも記載のある以下です。(番号 59.~61.)
{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "UnicornBasket", "type": "object", "properties": { "uuid": { "type": "string" } } }
5.3. Refactor Spaces サービスの作成(後半)
最後の Lambda 関数 GetUnicornBasket 向けのサービスを作成します。
先程の 2 つとほぼ変わりありませんが、ここでは「子パスを含める」にチェックを入れるのを忘れないようにしてください。(番号 62. )
5.4. API Gateay API 各種設定変更
このステップでは以下を行います。
- /unicorns/basket/{proxy+} - GET の「Lambda プロキシ統合の使用」のチェックを外す(番号 64.~66.)
- /unicorns/basket - POST の「Lambda プロキシ統合の使用」のチェックを外す(番号 67.)
- /unicorns/basket - DELETE の「Lambda プロキシ統合の使用」のチェックを外す(同上)
- /unicorns/basket/{proxy+} - GET の統合リクエストでマッピングテンプレートを作成(番号 68.~72.)
- /unicorns/basket - GET の削除(番号 73.~74.)
- /unicorns/basket/{proxy+} - GET のメソッドレスポンスに 200 を追加(番号 75.~76.)
- /unicorns/basket - POST のメソッドレスポンスに 200 を追加(番号 77.)
- /unicorns/basket - DELETE のメソッドレスポンスに 200 を追加(同上)
- /unicorns/basket/ の CORS の有効化(番号 78.~79.)
- /unicorns/basket/{proxy+} の CORS の有効化(番号 80.)
- /(ルート)での API のデプロイ(番号 81.~82.)
これらの手順は全部取り上げると冗長になるので、自分がスクショをとっていた部分をかいつまんで取り上げます。元の手順書を補完する形で参照してください。
/unicorns/basket/{proxy+} - GET の統合リクエストを選択する(番号 65.)時のイメージ。
/unicorns/basket/{proxy+} - GET の統合リクエストでマッピングテンプレートを作成する(番号 68.~72.)際のイメージ。
番号 72. で入力するテンプレートの中身は以下です。
#set($inputRoot = $input.path('$')) { "uuid" : "$input.params('proxy')" }
/unicorns/basket/ の CORS の有効化(番号 78.~79.)の際の一連のイメージ。
ここまでの手順で、切り替えが完了しています。1.2.で確認した Web ページでカートへの追加、削除、一覧表示を行う際は EC2 ではなくそれぞれの Lambda 関数にアクセスが振り分けられます。
Lambda 関数の初回立ち上げに時間がかかるため、切り替え後に初めて操作をする際はレスポンスが返ってくるまでちょっと待ちましょう。
ここまででハンズオンは完了です!
ハンズオンで作成されたリソースを覗く
ハンズオンを流し終わったので削除に移りたいところですが、せっかくなので作成されたリソースを眺めてみます。
Refactor Spaces 関連リソース
Refactor Spaces の最上位リソースとして環境(Enviroment)があり、環境に紐づく Transit Gateway が作成される。環境にはアプリケーションが含まれる。
↑環境はリソースベースポリシーを持ち、アカウントをまたいだ共有ができる。
アプリケーションにはネットワークロードバランサーやプロキシとなる API Gateway エンドポイントが紐づく。アプリケーションにはサービスおよびルートが含まれる。サービスは対象リソースが存在する AWS アカウントで作成する。
Refactor Spaces の全体像が分かってきました。
ネットワークロードバランサー
Refactor Spaces アプリケーションによって作成される NLB を確認します。
今回の構成ではプロキシの後段に控えるのが EC2 のパブリック DNS や非 VPC な Lambda 関数であったため特に使われていないはずです。
リスナーが何も設定されていませんでした。また、モニタリングから各種 CloudWatch メトリクスを確認しましたがすべて 0 でした。
「統合サービス」タブを参照すると、VPC エンドポイントサービスと統合されていることが分かります。
エンドポイントサービスの内訳を確認すると、エンドポイント接続として969236854626
が所有する VPC エンドポイントが表示されています。
知らない AWS アカウント番号だな?と思って調べたところ以下エントリがヒットし、API Gatway によるものだと判断が付きました。
Refactor Spaces 用サービスリンクロール
サービスリンクロールAWSServiceRoleForMigrationHubRefactorSpaces
には、AWS 管理ポリシーAWSMigrationHubRefactorSpacesServiceRolePolicy
がアタッチされています。
その内訳は以下となっています。VPC 関連やTransit Gateway、ELB や RAM に API Gatway など、関連リソースに対して必要な権限を持っていることが分かります。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:DescribeNetworkInterfaces", "ec2:DescribeRouteTables", "ec2:DescribeSubnets", "ec2:DescribeSecurityGroups", "ec2:DescribeVpcEndpointServiceConfigurations", "ec2:DescribeTransitGatewayVpcAttachments", "elasticloadbalancing:DescribeTargetHealth", "elasticloadbalancing:DescribeListeners", "elasticloadbalancing:DescribeTargetGroups", "ram:GetResourceShareAssociations" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ec2:AuthorizeSecurityGroupIngress", "ec2:RevokeSecurityGroupIngress", "ec2:DeleteSecurityGroup", "ec2:DeleteTransitGatewayVpcAttachment", "ec2:CreateRoute", "ec2:DeleteRoute", "ec2:DeleteTags", "ram:DeleteResourceShare", "ram:AssociateResourceShare", "ram:DisassociateResourceShare" ], "Resource": "*", "Condition": { "Null": { "aws:ResourceTag/refactor-spaces:environment-id": "false" } } }, { "Effect": "Allow", "Action": "ec2:DeleteVpcEndpointServiceConfigurations", "Resource": "*", "Condition": { "Null": { "aws:ResourceTag/refactor-spaces:application-id": "false" } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:RegisterTargets", "elasticloadbalancing:CreateLoadBalancerListeners", "elasticloadbalancing:CreateListener", "elasticloadbalancing:DeleteListener", "elasticloadbalancing:DeleteTargetGroup" ], "Resource": "*", "Condition": { "StringLike": { "aws:ResourceTag/refactor-spaces:route-id": [ "*" ] } } }, { "Effect": "Allow", "Action": [ "apigateway:PUT", "apigateway:POST", "apigateway:GET", "apigateway:PATCH", "apigateway:DELETE" ], "Resource": [ "arn:aws:apigateway:*::/restapis", "arn:aws:apigateway:*::/restapis/*", "arn:aws:apigateway:*::/vpclinks/*", "arn:aws:apigateway:*::/tags", "arn:aws:apigateway:*::/tags/*" ], "Condition": { "Null": { "aws:ResourceTag/refactor-spaces:application-id": "false" } } }, { "Effect": "Allow", "Action": "apigateway:GET", "Resource": "arn:aws:apigateway:*::/vpclinks/*" }, { "Effect": "Allow", "Action": "elasticloadbalancing:DeleteLoadBalancer", "Resource": "arn:*:elasticloadbalancing:*:*:loadbalancer/net/refactor-spaces-nlb-*" }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:AddTags", "elasticloadbalancing:CreateListener" ], "Resource": "arn:*:elasticloadbalancing:*:*:loadbalancer/net/refactor-spaces-nlb-*", "Condition": { "Null": { "aws:RequestTag/refactor-spaces:route-id": "false" } } }, { "Effect": "Allow", "Action": "elasticloadbalancing:DeleteListener", "Resource": "arn:*:elasticloadbalancing:*:*:listener/net/refactor-spaces-nlb-*" }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:DeleteTargetGroup", "elasticloadbalancing:RegisterTargets" ], "Resource": "arn:*:elasticloadbalancing:*:*:targetgroup/refactor-spaces-tg-*" }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:AddTags", "elasticloadbalancing:CreateTargetGroup" ], "Resource": "arn:*:elasticloadbalancing:*:*:targetgroup/refactor-spaces-tg-*", "Condition": { "Null": { "aws:RequestTag/refactor-spaces:route-id": "false" } } } ] }
Refactor Spaces が何をしてくれるのかがここからぼんやり分かってきますね。リソースタグで条件付けをしているのが印象的です。
ハンズオン環境の削除
構築した環境は(すべてではありませんが)残っているだけでも料金が発生します。忘れずにお掃除しましょう。手順書を参考に、以下の順番で消していってください。
- Lambda 関数 3 つ
- Refactor Spaces のルート 4 つ
- ソースパス
/
は最後に消す
- ソースパス
- Refactor Spaces のサービス 4 つ
- legacy は最後に消す
- Refactor Spaces アプリケーション(数分かかります)
- Refactor Spaces 環境(数分かかります)
- S3 バケット 2 つを空にする
- CloudFormation スタック 2 つ(並行で削除可)
- スタック MonoToMicro は 10 分程度かかります
- (MonoToMicro-InstanceLogGroup-xxxxxx はスタックにあわせて削除されます)
Refactor Spaces を手軽に試せて助かるハンズオンでした
長丁場になりましたが、Refactor Spaces ハンズオンの手順をおさらいしてみました。おかげさまで Refactor Spaces を何となく理解できた気がします。
一番のネックとなるアプリケーションの準備を済ませてくれているのが大変助かります。普段 API Gatway を触らないので、その手順も整備されているのも嬉しいです。
ベースとなる英語のワークショップは以下なのですが、初見だとなかなかハードルを感じます。分かりやすく日本語の手順に落とし込んでくれていることに感謝です。
寄り道しながらでも 90 分程度あれば一通り試せたので、興味があればチャレンジしてみてください。
以上、 チバユキ (@batchicchi) がお送りしました。